#pragma once
#ifndef _IMAGE_UTILS_H_
#define _IMAGE_UTILS_H_
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif // WIN32

#include <QLabel>
#include <iostream>
#include <opencv2/opencv.hpp>
#include "MyError.h"
#include "configuration.h"


using namespace std;

/**
 * 图片处理通用工具类
 */
namespace ImageUtils {
    

    /// <summary>
    /// 保存图像
    /// </summary>
    /// <param name="name"></param>
    /// <param name="image"></param>
    void saveImage(QString name, cv::Mat& image);


    /// <summary>
    /// 显示图像
    /// </summary>
    /// <param name="name"></param>
    /// <param name="img"></param>
    void showImg(QString name, cv::Mat& img);


    /// <summary>
    /// 对一组数据进行滤波
    /// </summary>
    /// <typeparam name="T">数据类型，整形，浮点型</typeparam>
    /// <param name="origin">原始数据</param>
    /// <param name="dstData">滤波后的数据</param>
    /// <param name="step"></param>
    template <typename T>
    void aveFilter(vector<T>& origin, vector<float>& dstData, int step);


    /// <summary>
    /// 计算图像的平均灰度值
    /// </summary>
    /// <param name="inputImg"></param>
    /// <returns></returns>
    int calculateImageAveGrayVal(cv::Mat& inputImg);


    /// <summary>
    /// 在图片上指定位置绘制文本
    /// </summary>
    /// <param name="inputImg">源图片</param>
    /// <param name="postion">绘制文本的位置</param>
    /// <param name="text">要绘制的文本</param>
    /// <param name="color">文本的颜色</param>
    void drawText(cv::Mat& inputImg, cv::Point& postion, QString& text, cv::Scalar& color = cv::Scalar(0, 0, 255));


    /// <summary>
    /// 将图片显示到QLabel上
    /// </summary>
    /// <param name="label">要显示图片的label</param>
    /// <param name="img">源图片</param>
    /// <param name="format">图片显示格式</param>
    void liveImage(QLabel* label, cv::Mat& img, QImage::Format format = QImage::Format_BGR888);


    /// <summary>
    /// 修改Label的尺寸，使其尺寸和图像比例相同
    /// </summary>
    /// <param name="label"></param>
    /// <param name="image"></param>
    void resizeLabelSize(QLabel* label, cv::Mat& image);


    /// <summary>
    /// 通过修改QLabel的尺寸，将图片等比例显示到QLabel上
    /// </summary>
    /// <param name="label"></param>
    /// <param name="image"></param>
    /// <param name="format"></param>
    void resizeLabelSizeAndLiveImage(QLabel* label, cv::Mat& image, QImage::Format format = QImage::Format_BGR888);


    /// <summary>
    /// 找轮廓
    /// </summary>
    /// <param name="inputImg">输入图像</param>
    /// <param name="contours">输出轮廓</param>
    void findContours(cv::Mat& inputImg, vector<vector<cv::Point>>& contours);


    /// <summary>
    /// 通过宽度找图像上的最大轮廓
    /// </summary>
    /// <param name="inputImg">输入二值图像</param>
    /// <param name="outputContours">返回轮廓</param>
    void findMaxContourByWidth(cv::Mat& inputImg, vector<vector<cv::Point>>& outputContours);


    /// <summary>
    /// 通过轮廓的面积确定最大轮廓
    /// </summary>
    /// <param name="inputImg"></param>
    /// <param name="outputContours"></param>
    void findMaxContourByArea(cv::Mat& inputImg, vector<vector<cv::Point>>& outputContours);


    // ============================================================================================================
    // 提取中心点
    void findCenterPoint(int num, cv::Mat& srcImage, float threshold, std::vector<cv::Vec2f>& centerPoints);

    /// <summary>
    /// 滤波图像
    /// </summary>
    /// <param name="img">输入图像</param>
    /// <param name="threshold">设定阈值</param>
    cv::Mat downwardThreFileter(const cv:: Mat & img,int threshold);

    /// <summary>
    /// 过滤点集
    /// </summary>
    /// <param name="points">输入点集</param>
    /// <param name="distanceThreshold">阈值</param>
    /// <returns></returns>
    std::vector<cv::Point2f> filterTailPoints(const std::vector<cv::Point2f>& points, float distanceThreshold);

    // 按照Y坐标对点进行排序
    void sortPointsByY(std::vector<cv::Point2f>& points);

    /// <summary>
   /// 计算两点之间的欧氏距离
   /// </summary>
   /// <param name="p1">坐标点1</param>
   /// <param name="p2">坐标点2</param>
   /// <returns></returns>
    double euclideanDistance(const cv::Point2f& p1, const cv::Point2f& p2);

    /// <summary>
    /// 提取激光线中心点集
    /// </summary>
    /// <param name="img">输入图像</param>
    /// <returns></returns>
    std::vector<cv::Point2f> GrayScaleCenter(const cv::Mat& img);

    // 单纯的标准最大值法实现(更简单的版本)
    std::vector<cv::Point2f> simpleMaxValueMethod(const cv::Mat& inputImage);

    // 计算实际高度
    float calculateHeight(float imageHeight, const ImageProcessConfig& IPC);

    //线性插值
    std::vector<cv::Point> linearInterpolation(const cv::Point& p1, const cv::Point& p2);


    // 封装函数：处理断开点并插值，返回插值点和原始点的合并结果（去重且排序）
    std::vector<cv::Point2f> interpolatePoints(std::vector<cv::Point2f>& points, int threshold);


}

#endif